#include <stdlib.h>
#include <cmath>
#include "encode.h"

#ifdef __cplusplus
extern "C"{
  #endif
  enum{
    ROW_OK,
    ROW_NOTSUPPORTED,
    ROW_INVALIDCODE,
    ROW_INVALIDARGUMENT,
    ROW_INTERNALERROR,
    ROW_NOMEMORY
  };
  #ifdef __cplusplus
}
#endif

//the parameter radius represent width(difference of x) if the sample area is rectangle
int geo_neighbors(unsigned long* code, unsigned int xLength, unsigned int yLength, unsigned char size, unsigned long* neiCode, unsigned int* upMax, unsigned int* rightMax, double radius, double width,double height = 0);

//xi begin form 0; also does yi
static int  encode_impl(double xMax, unsigned int xLength, unsigned char size, double x, double y, unsigned long* code){
  unsigned int xi = (x / size); unsigned int yi = (y / size);
  *code = yi*xLength + xi;
  
  return ROW_OK;
}

//encode as the row style
int encode(double xMax, unsigned int xLength, unsigned char size, double x, double y, unsigned long* code){
  return encode_impl(xMax, xLength, size, x, y, code);
}

static int geo_neighbors_impl(unsigned long* code, unsigned int xLength, unsigned int yLength, unsigned char size, unsigned long* neiCode, unsigned int* upMax, unsigned int* rightMax, double radius, double width,double height){
  
  unsigned int xi; unsigned int yi;
  if (*code == 0){
    xi = 0; yi = 0;
  }
  else{
    xi = *code%xLength;
    yi = (*code / xLength);
  }
  
  unsigned int stepLength=2;
  if (height != 0) {
  radius = width;//rectangle model, width instead radius
	stepLength = ceil(radius / size);
  }
  
  unsigned int xStep;
  if (radius >= xi*size) xStep = xi;
  else xStep = stepLength;
  
  if ((xLength - 1 - xi) > stepLength){ *rightMax = stepLength + xStep + 1; }
  else *rightMax = (xLength - xi) + xStep;
  
  if (height != 0){
    stepLength = ceil(height / size);
    radius = height;
  }//in the rectangle model, stepLenth in the vertical direction is not the same as the horizontal.
  unsigned int yStep;
  if (radius >= yi*size) { yStep = yi; }
  else yStep = stepLength;
  
  if ((yLength -1 - yi) > stepLength) { *upMax = stepLength + yStep +1; }
  else *upMax = (yLength - yi) + yStep;
  
  *neiCode = *code - yStep*xLength - xStep;
  return ROW_OK;
}

int geo_neighbors(unsigned long* code, unsigned int xLength, unsigned int yLength, unsigned char size, unsigned long* neiCode, unsigned int* upMax, unsigned int* rightMax, double radius, double width,double height){
  return geo_neighbors_impl(code, xLength, yLength, size, neiCode, upMax, rightMax, radius, width,height);
}